﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;

namespace KATS_Client.FileNameData
{
    /// <summary>
    /// Info extracted from a filename
    /// </summary>
    public class FileNameInfo
    {
        /// <summary>The original file name</summary>
        public string FileName = string.Empty;
        /// <summary>The series name</summary>
        public string Series = string.Empty;
        /// <summary>The season number</summary>
        public int Season = 0;
        /// <summary>The episode number</summary>
        public int Episode = 0;


        /// <summary>Create a file info object</summary>
        /// <param name="series">Series name</param>
        /// <param name="season">Season number</param>
        /// <param name="episode">Episode number</param>
        private FileNameInfo(string FileName, string series, int season, int episode)
        {
            this.FileName = FileName;
            this.Series = series;
            this.Season = season;
            this.Episode = episode;
        }

        /// <summary>Create an empty file info object</summary>
        private FileNameInfo()
        {

        }


        /// <summary>Parse a filename</summary>
        /// <returns>A data file</returns>
        public static FileNameInfo Parse(string Filename)
        {
            FileNameInfo data = new FileNameInfo();
            data.FileName = Filename;

            string message = Filename;

            List<string> SeasonEpisodeStrings = new List<string>();

            Regex[] SeasonEpisodeExpressions = new Regex[2];

            SeasonEpisodeExpressions[0] = new Regex("[0-9]+x[0-9]+", RegexOptions.IgnoreCase);
            SeasonEpisodeExpressions[1] = new Regex("S[0-9]+E[0-9]+", RegexOptions.IgnoreCase);

            // remove the file extension from the string
            FileInfo fi = new FileInfo(Filename);
            message = message.Remove(Filename.Length - fi.Extension.Length);


            // now look for [...] and remove all data in these brackets
            bool found = false;
            do
            {
                // reset found to be false
                found = false;

                // look for the [ and ]
                int pos = -1;

                int pos2 = message.IndexOf("]");

                if (pos2 > 0)
                {
                    // then a ] was found
                    // now work backwards and find its pairing [
                    for (int i = pos2 - 1; i >= 0; i--)
                    {
                        if (message[i] == '[')
                        {
                            pos = i;

                            string text = message.Substring(i + 1, pos2 - pos - 1);
                            foreach (Regex r in SeasonEpisodeExpressions)
                            {
                                if (r.IsMatch(text, 0))
                                {
                                    SeasonEpisodeStrings.Add(r.Match(text).Value);
                                    break;
                                }
                            }

                            break;
                        }
                    }
                }
                if (pos >= 0 && pos2 >= 0 && pos < pos2)
                {
                    // then [ and ] are in the page in that order
                    found = true;

                    // remove the [..] from the string
                    message = message.Remove(pos, (pos2 - pos + 1));
                }
            }
            while (found);



            // now convert all full stops and _ [underscores] to spaces
            string[] spaceChars = new string[] { ".", "_" };

            foreach (string c in spaceChars)
            {
                message = message.Replace(c, " ");
            }



            // trim off ending characters
            char[] trimChars = new char[] { ' ', '-' };
            message = message.Trim(trimChars);



            // now find the 1st block of text, represents the series name
            // often separated by a -
            string[] messageBlocks = message.Split(new char[] { '-' });
            if (messageBlocks.Length > 1)
            {
                int pos = 0;
                while (true)
                {
                    string name = messageBlocks[pos].Trim();
                    Regex nameExpression = new Regex("[0-9]+");
                    MatchCollection matches = nameExpression.Matches(name);
                    foreach (Match m in matches)
                    {
                        name = name.Replace(m.Value, "");
                    }

                    bool foundspaces = false;
                    do
                    {
                        foundspaces = false;
                        if (name.Contains("  "))
                        {
                            name = name.Replace("  ", " ");
                            foundspaces = true;
                        }
                    }
                    while (foundspaces);
                    name = name.Trim();
                    data.Series = name;

                    if (name != string.Empty)
                        break;

                    pos++;

                }
            }
            else
            {
                // filename could not be derrived from - placement
                // so use first set of letters in the string that make up words

                // split by spaces
                string[] x = message.Split(new char[] { ' ' });

                if (x.Length > 1)
                {
                    // only do this if there are more than 1 words/sections in the text
                    bool fileNameEndFound = false;

                    int i = 1;
                    for (; i < x.Length; i++)
                    {
                        // check each string section
                        Regex containsNumber = new Regex("[0-9]+");
                        MatchCollection coll = containsNumber.Matches(x[i]);
                        if (coll.Count > 0)
                        {
                            // then this string sample contains a number
                            // so stop the system
                            i--;
                            fileNameEndFound = true;
                            break;
                        }
                    }

                    if (fileNameEndFound)
                    {
                        string name = string.Empty;
                        // then join all the sections together using spaces up to i
                        for (int j = 0; j <= i; j++)
                        {
                            name += x[j] + " ";
                        }
                        name = name.Trim(trimChars);
                        data.Series = name;
                    }
                    else
                    {
                        Console.WriteLine("Unable to extract name from filename. {0}", data.FileName);
                        return null;
                        //throw new NotSupportedException("Could not derrive a name for this series");
                    }
                }
            }


            // so do pattern searches for the regular expressions
            foreach (Regex r in SeasonEpisodeExpressions)
            {
                if (r.IsMatch(message))
                {
                    Match m = r.Match(message);

                    // the value matches the regular expression
                    // so save it
                    // and then remove it from the text
                    SeasonEpisodeStrings.Add(m.Value);
                    message = message.Replace(m.Value, "");
                    break;
                }
            }


            // try searching for a single numerical value
            // spliting into different blocks using 
            char[] numsearch = new char[] { ' ', '-' };
            string[] parts = message.Split(numsearch);
            foreach (string s in parts)
            {
                int num;
                if (int.TryParse(s, out num))
                {
                    // so the number successfully parsed to an integer
                    // so presume this is the episode number
                    SeasonEpisodeStrings.Add(num.ToString());
                    break;
                }
            }





            // convert the season episode string into the season/episode values
            if (SeasonEpisodeStrings.Count > 0)
            {
                // then a possible string containing episode or string data has been found
                foreach (string s in SeasonEpisodeStrings)
                {
                    // if there are 2 separate numbers
                    //  the 1st number is the season number
                    //  the 2nd number is the episode number
                    // if there is 1 number
                    //  then it is the episode number, and season number is 1

                    // if there is 1 number of 3 digits in length then may be the episode
                    // number, in Naruto etc, or maybe season and episode together

                    Regex numbers = new Regex("[0-9]+");
                    MatchCollection numbersC = numbers.Matches(s);

                    int season = 0;
                    int episode = 1;

                    if (numbersC.Count == 2)
                    {
                        // then 2 numbers detected
                        season = int.Parse(numbersC[0].Value);
                        episode = int.Parse(numbersC[1].Value);
                    }
                    else if (numbersC.Count == 1)
                    {
                        // then only 1 number detected
                        int number = int.Parse(numbersC[0].Value);
                        episode = number;
                    }

                    if (season >= 0 && season <= 50)
                    {
                        // then the season is a valid number so save and return data
                        data.Season = season;
                        data.Episode = episode;
                        break;
                    }
                }
            }

            return data;
        }




        /// <summary>
        /// Get a hash code for this object
        /// </summary>
        /// <returns>Hash Code</returns>
        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }

        /// <summary>
        /// Equals
        /// </summary>
        /// <param name="obj">Object to compare to</param>
        /// <returns>Equals?</returns>
        public override bool Equals(object obj)
        {
            if (obj == null)
                return false;
            return this.ToString() == obj.ToString();
        }

        /// <summary>
        /// To String
        /// </summary>
        /// <returns>string</returns>
        public override string ToString()
        {
            return string.Format("{0} s{1}e{2}", Series, Season, Episode);
        }
    }
}
